package com.twu.biblioteca;

import java.util.*;
import java.util.List;

/**
 * Created by kathy on 12/04/14.
 * Assumption: Each book has ONLY ONE copy stored in Biblioteca system.
 */
public class BibliotecaApp {

    private static List<User> userList;

    private static Library library;

    private static Map<Integer,Action> actions;
    private static IConsoleReader consoleReader;

    // global variable stores current user and will be released until QUIT option is chosen
    protected static User currentUser;

    // this method is to support mock test
    public static void setConsoleReader(IConsoleReader consoleReader1){
        consoleReader = consoleReader1;
    }

    private static void init(){

        List<Book> bookRepository = new ArrayList<Book>() {
            {
                add(new Book(new StringBuilder("E00012"),
                        new StringBuilder("Vocabulary for IELTS"),
                        new StringBuilder("Anneli Williams"),
                        1));
                add(new Book(new StringBuilder("E00045"),
                        new StringBuilder("Understanding Australia"),
                        new StringBuilder("Sally A. White"),
                        1));
                add(new Book(new StringBuilder("T01005"),
                        new StringBuilder("Unix System"),
                        new StringBuilder("Mark Sobell"),
                        1));
            }};

        List<Movie> movieRepository = new ArrayList<Movie>() {{
            add(new Movie(new StringBuilder("MO1234"),
                    new StringBuilder("Noah"),
                    2014,
                    new StringBuilder("Darren Aronofsky"),
                    Rating.R7));
            add(new Movie(
                    new StringBuilder("MO1222"),
                    new StringBuilder("Frozen"),
                    2013,
                    new StringBuilder("Chris Buck"),
                    Rating.R8));
            add(new Movie(new StringBuilder("MO0223"),
                    new StringBuilder("Avatar"),
                    2009,
                    new StringBuilder("James Cameron"),
                    Rating.R8));
        }};

         userList = new ArrayList<User>(){{
            add(new User(new StringBuilder("111-2233"),
                    new StringBuilder("Alex"),
                    new StringBuilder("alex@gmail.com"),
                    new StringBuilder("0448234111"),
                    new StringBuilder("abc")));
            add(new User(new StringBuilder("119-4821"),
                    new StringBuilder("Mary"),
                    new StringBuilder("m@gmail.com"),
                    new StringBuilder("0403555312"),
                    new StringBuilder("abc")));
            add(new User(new StringBuilder("Ben"),
                    new StringBuilder("301-5312"),
                    new StringBuilder("ben@hotmail.com"),
                    new StringBuilder("0401540329"),
                    new StringBuilder("abc")));
        }};

        library = new Library(bookRepository, movieRepository, userList);
        initActions();
        consoleReader = new ConsoleReader();
    }



    private static void initActions(){

        actions = new HashMap<Integer,Action>();

        actions.put(MenuOptions.LIST_BOOKS.getCode(),
                    new ListBooksAction(library));

        actions.put(MenuOptions.CHECKOUT_BOOKS.getCode(),
                    new CheckoutBookAction(library, new ConsoleReader(), new ConsoleWriter(), new UserLogin(userList)));

        actions.put(MenuOptions.RETURN_BOOKS.getCode(),
                    new ReturnBookAction(library, new ConsoleReader(), new ConsoleWriter(), new UserLogin(userList)));

        actions.put(MenuOptions.LIST_MOVIES.getCode(),
                    new ListMoviesAction(library));

        actions.put(MenuOptions.CHECKOUT_MOVIE.getCode(),
                    new CheckoutMovieAction(library, new ConsoleReader(), new ConsoleWriter()));

        actions.put(MenuOptions.USER_INFO.getCode(),
                    new UserInformation(new ConsoleWriter()));

        actions.put(MenuOptions.USER_LOGIN.getCode(),
                    new UserLogin(userList));

        actions.put(MenuOptions.QUIT.getCode(),
                    new QuitAction());

        actions.put(null, new InvalidAction());
    }

    private static void printOptions() {

        System.out.println("\n Please choose one of the following option by " +
                "pressing its number to use the system.");

        for(MenuOptions menu : MenuOptions.values()){
            if(menu != MenuOptions.USER_INFO
                    || (menu == MenuOptions.USER_INFO && BibliotecaApp.currentUser != null))
               menu.printOption();
        }
    }

    // This method returns an Integer with value = null if input is not a valid option.
    public static Integer getMenuOptionFromInput(){

        Integer optionChosen = null;
        try {
            String input =  consoleReader.readInput();
            int number = Integer.parseInt(input);

            // check if input is a valid option
            if(number >= MenuOptions.LIST_BOOKS.getCode() && number <= MenuOptions.QUIT.getCode()) {
                optionChosen = number;
            }

        } catch (NumberFormatException e){
            optionChosen = null;
        }
        return optionChosen;
    }

    public static void main(String[] args) {

        init();

        System.out.println("Welcome to Biblioteca from Bangalore Public Library!");
        printOptions();

        Integer optionChosen = getMenuOptionFromInput();

        // loop until user choose QUIT
        while((optionChosen != null && optionChosen != MenuOptions.QUIT.getCode())
                || optionChosen == null) {

            // requires user login if user checkouts or returns book.
            if(optionChosen != null
                && (optionChosen == MenuOptions.CHECKOUT_BOOKS.getCode() || optionChosen == MenuOptions.RETURN_BOOKS.getCode())
                && currentUser == null){

                UserLogin userLogin = new UserLogin(userList);
                currentUser = userLogin.login();
            }

            // user information option can't be shown in menu if user haven't logged in successfully.
            if(optionChosen == MenuOptions.USER_INFO.getCode() && BibliotecaApp.currentUser == null)
                optionChosen = null;

            Action action = actions.get(optionChosen);
            action.execute();
            printOptions();
            optionChosen = getMenuOptionFromInput();
        }

        // option chosen is Quit
        actions.get(optionChosen).execute();
    }

}
